﻿using ComLib.ComFun;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;

namespace ComLib.ComType
{
    public class ShareMemory
    {
        [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct ShareMonoryData
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5 * 1024 * 1024)]
            public byte[] data;

            //[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public int dataLen;

            public void ShareData()
            {
                data = new byte[5 * 1024 * 1024];
                dataLen = 0;
            }
        }

        const int INVALID_HANDLE_VALUE = -1;
        const int PAGE_READWRITE = 0x04;
        //共享内存
        [DllImport("Kernel32.dll", EntryPoint = "CreateFileMapping")]
        private static extern IntPtr CreateFileMapping(IntPtr hFile, //HANDLE hFile,
            UInt32 lpAttributes,//LPSECURITY_ATTRIBUTES lpAttributes,  //0
            UInt32 flProtect,//DWORD flProtect
            UInt32 dwMaximumSizeHigh,//DWORD dwMaximumSizeHigh,
            UInt32 dwMaximumSizeLow,//DWORD dwMaximumSizeLow,
            string lpName//LPCTSTR lpName
        );

        [DllImport("Kernel32.dll", EntryPoint = "OpenFileMapping")]
        private static extern IntPtr OpenFileMapping(
            UInt32 dwDesiredAccess,//DWORD dwDesiredAccess,
            int bInheritHandle,//BOOL bInheritHandle,
            string lpName//LPCTSTR lpName
        );

        const int FILE_MAP_ALL_ACCESS = 0x0002;
        const int FILE_MAP_WRITE = 0x0002;

        [DllImport("Kernel32.dll", EntryPoint = "MapViewOfFile")]
        private static extern IntPtr MapViewOfFile(
            IntPtr hFileMappingObject,//HANDLE hFileMappingObject,
            UInt32 dwDesiredAccess,//DWORD dwDesiredAccess
            UInt32 dwFileOffsetHight,//DWORD dwFileOffsetHigh,
            UInt32 dwFileOffsetLow,//DWORD dwFileOffsetLow,
            UInt32 dwNumberOfBytesToMap//SIZE_T dwNumberOfBytesToMap
        );

        [DllImport("Kernel32.dll", EntryPoint = "UnmapViewOfFile")]
        private static extern int UnmapViewOfFile(IntPtr lpBaseAddress);

        [DllImport("Kernel32.dll", EntryPoint = "CloseHandle")]
        private static extern int CloseHandle(IntPtr hObject);

        //private Semaphore m_Write;  //可写的信号
        //private Semaphore m_Read;  //可读的信号

        private IntPtr handle;     //文件句柄
        private IntPtr addr;       //共享内存地址

        public const int dataLength = 5 * 1024 * 1024;            //共享内存长
        //const int maxLength = 6 * 1024 * 1024;
        private bool _bInit = false;
        //Thread threadRev;
        byte[] byteStr = new byte[dataLength];

        public ShareMemory(bool bWrite)
        {
            InitShareMem(bWrite);
        }
        private void InitShareMem(bool bWrite)
        {

            //mapLength = 1024;
            //_bExit = false;
            if (bWrite)
            {
                ////m_Write = new Semaphore(1, 1, "WriteMap");//开始的时候有一个可以写
                //m_Read = new Semaphore(0, 1, "ReadMap");//没有数据可读

                IntPtr hFile = new IntPtr(INVALID_HANDLE_VALUE);
                handle = CreateFileMapping(hFile, 0, PAGE_READWRITE, 0, dataLength, "shareMemory");
                addr = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);

            }
            else
            {
                //handle = OpenFileMapping(FILE_MAP_WRITE, 0, "shareMemory");
                //addr = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);

                //m_Write = Semaphore.OpenExisting("WriteMap");
                //m_Read = Semaphore.OpenExisting("ReadMap");

                handle = OpenFileMapping(0x0002, 0, "shareMemory");
                addr = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
            }
            _bInit = true;
        }

        public byte[] GetShareMemData()
        {
            try
            {

                //读取共享内存中的数据：
                //是否有数据写过来
                //m_Read.WaitOne();

                //if (_bExit)
                //{
                //    return null;
                //}

                if (addr == IntPtr.Zero)
                {
                    return null;
                }

                lock (_objlock)
                {
                    Marshal.Copy(addr, byteStr, 0, dataLength);
                    /////调用数据处理方法 处理读取到的数据
                    GC.Collect();
                }


                //m_Write.Release();

                return byteStr;
            }
            catch (SemaphoreFullException e)
            {
                //    continue;
                //    //Thread.Sleep(0);
                return byteStr;
            }
        }

        public void CopyData2Mem(ShareMonoryData shareData)
        {
            try
            {
                byte[] data = IPCCom.StructToBytes(shareData);
                Marshal.Copy(data, 0, addr, data.Length);
                GC.Collect();

                // m_Read.Release();
            }
            catch (SemaphoreFullException e)
            {

            }
        }

        private static object _objlock = new object();

        public void CopyData2Mem(byte[] data)
        {
            lock (_objlock)
            {
                Marshal.Copy(data, 0, addr, data.Length);
                GC.Collect();
            }
        }

        static unsafe void byteCopy(byte[] dst, IntPtr src)
        {
            fixed (byte* pDst = dst)
            {
                byte* pdst = pDst;
                byte* psrc = (byte*)src;
                while ((*pdst++ = *psrc++) != '\0') ;
            }
        }

        static unsafe void Copy(byte[] byteSrc, IntPtr dst)
        {
            fixed (byte* pSrc = byteSrc)
            {
                byte* pDst = (byte*)dst;
                byte* psrc = pSrc;
                for (int i = 0; i < byteSrc.Length; i++)
                {
                    *pDst = *psrc;
                    pDst++;
                    psrc++;
                }
            }
        }

        /// <summary>
        /// 关闭共享内存
        /// </summary>
        //private bool _bExit = false;
        public void Close()
        {
            if (_bInit)
            {
                UnmapViewOfFile(addr);
                CloseHandle(handle);
            }
        }
    }
}
